package com.miku.mq.producer;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.miku.model.entity.Chart;
import com.miku.model.enums.ChartStatusEnum;
import com.miku.service.ChartService;
import com.miku.service.TextTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Component
@Slf4j
public class MessageProducer {


    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Resource
    private ChartService chartService;


    /**
     * 发送消息-生成图表的消息
     * @param exchange
     * @param routingKey
     * @param message
     */
    public void sendMessage(String exchange,String routingKey,String message){
        Long id=Long.parseLong(message);
        //消息Id，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        // 3.添加callback
        correlationData.getFuture().addCallback(
                result -> {
                    if(result.isAck()){
                        // 3.1.ack，消息成功
                        log.debug("消息发送成功, ID:{}", correlationData.getId());
                    }else{
                        // 3.2.nack，消息失败,保存到数据库中
                        handleChartErrorByMq(id,"消息发送失败");
                        log.error("消息发送失败, ID:{}, 原因{}",correlationData.getId(), result.getReason());
                    }
                },

                ex -> {log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),ex.getMessage());
                        handleChartErrorByMq(id,"消息发送异常");
                }
        );

        rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
        // 休眠一会儿，等待ack回执
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),e);
        }
    }

    /**
     * 发送消息-生成文本消息
     *
     * @param exchange
     * @param routingKey
     * @param size
     */

    public void sendMessageToBi(String exchange, String routingKey, Long taskId, Long textTaskId, int size){
        //消息Id，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        // 3.添加callback
        correlationData.getFuture().addCallback(
                result -> {
                    if(result.isAck()){
                        // 3.1.ack，消息成功
                        log.debug("消息发送成功, ID:{}", correlationData.getId());
                    }else{
                        // 3.2.nack，消息失败,保存到数据库中
                        handleChartErrorByMq(textTaskId,"消息发送失败");
                        log.error("消息发送失败, ID:{}, 原因{}",correlationData.getId(), result.getReason());
                    }
                },

                ex -> {log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),ex.getMessage());
                    handleChartErrorByMq(textTaskId,"消息发送异常");
                }
        );
        //封装成map集合
        Map<String,String> map=new HashMap<>();
        map.put("textTaskId",textTaskId.toString());
        map.put("size",Integer.toString(size));
        String message = JSONUtil.toJsonStr(map);
        //发送消息
        rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
        // 休眠一会儿，等待ack回执
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),e);
        }
    }

    /**
     * 修改失败,改数据库的状态为失败
     */

    private void handleChartErrorByMq(Long chartId,String execMessage) {
        //修改数据库状态失败
        boolean update = chartService.update(Wrappers.<Chart>lambdaUpdate()
                .eq(Chart::getId, chartId)
                .set(Chart::getStatus, ChartStatusEnum.FAILED.getValue())
                .set(Chart::getExecMessage, execMessage));
        if (!update){
            log.error("更新图表状态为失败,失败,chartId:{}",chartId);
        }

    }
}
